// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include <zencore/filesystem.h>
#include <zencore/guid.h>
#include <zencore/iohash.h>
#include <zencore/string.h>
#include <zencore/uid.h>

ZEN_THIRD_PARTY_INCLUDES_START
#include <fmt/format.h>
ZEN_THIRD_PARTY_INCLUDES_END

#include <string_view>

// Custom formatting for some zencore types

template<typename T>
requires DerivedFrom<T, zen::StringBuilderBase>
struct fmt::formatter<T> : fmt::formatter<std::string_view>
{
	auto format(const zen::StringBuilderBase& a, format_context& ctx) const
	{
		return fmt::formatter<std::string_view>::format(a.ToView(), ctx);
	}
};

template<typename T>
requires DerivedFrom<T, zen::NiceBase>
struct fmt::formatter<T> : fmt::formatter<std::string_view>
{
	auto format(const zen::NiceBase& a, format_context& ctx) const
	{
		return fmt::formatter<std::string_view>::format(std::string_view(a), ctx);
	}
};

template<>
struct fmt::formatter<zen::IoHash> : formatter<string_view>
{
	template<typename FormatContext>
	auto format(const zen::IoHash& Hash, FormatContext& ctx)
	{
		zen::IoHash::String_t String;
		Hash.ToHexString(String);
		return fmt::formatter<string_view>::format({String, zen::IoHash::StringLength}, ctx);
	}
};

template<>
struct fmt::formatter<zen::Oid> : formatter<string_view>
{
	template<typename FormatContext>
	auto format(const zen::Oid& Id, FormatContext& ctx)
	{
		zen::StringBuilder<32> String;
		Id.ToString(String);
		return fmt::formatter<string_view>::format({String.c_str(), zen::Oid::StringLength}, ctx);
	}
};

template<>
struct fmt::formatter<zen::Guid> : formatter<string_view>
{
	template<typename FormatContext>
	auto format(const zen::Guid& Id, FormatContext& ctx)
	{
		zen::StringBuilder<48> String;
		Id.ToString(String);
		return fmt::formatter<string_view>::format({String.c_str(), zen::Guid::StringLength}, ctx);
	}
};

template<>
struct fmt::formatter<std::filesystem::path> : formatter<string_view>
{
	template<typename FormatContext>
	auto format(const std::filesystem::path& Path, FormatContext& ctx)
	{
		using namespace std::literals;

		zen::ExtendableStringBuilder<128> String;
		String << Path.u8string();
		std::string_view PathView = String.ToView();

		if (PathView.starts_with("\\\\?\\"sv))
		{
			PathView.remove_prefix(4);
		}

		return fmt::formatter<string_view>::format(PathView, ctx);
	}
};

template<typename T>
requires DerivedFrom<T, zen::PathBuilderBase>
struct fmt::formatter<T> : fmt::formatter<std::string_view>
{
	auto format(const zen::PathBuilderBase& a, format_context& ctx) const
	{
		return fmt::formatter<std::string_view>::format(a.ToView(), ctx);
	}
};
